package au.org.arcs.dss.provider.dataset.facade;

import java.util.*;

import au.org.arcs.dss.provider.cache.*;
import au.org.arcs.dss.provider.dataset.DataSet;
import au.org.arcs.dss.provider.ConfigManager;
import au.org.arcs.dss.provider.datasource.provider.factory.*;
import au.org.arcs.dss.provider.dataset.request.DataSetRequest;
import au.org.arcs.dss.provider.dataset.response.DataSetResponse;
import au.org.arcs.dss.provider.datasource.provider.DataSourceProvider;
import au.org.arcs.dss.provider.util.SystemUtils;

/**
 *
 * @author ming
 */
public class DataSetFacade {
  private CacheProvider cacheProvider;

  public DataSetResponse getDataSets(DataSetRequest request) {
    DataSetResponse response = new DataSetResponse();
    List<DataSet> dataSets = new ArrayList<DataSet>();

    if (request != null) {

      DataSourceProviderFactory dataSourceProviderFactory =
              DataSourceProviderFactoryLocator.getDataSourceProviderFactory();

      DataSourceProvider dataSourceProvider = dataSourceProviderFactory.getDataSourceProvider();
      dataSourceProvider.setProviderAccount(ProviderAccountFactory.getInstance());

      // @todo Security Check.
      boolean cacheEnabled = ConfigManager.getConfigManagerInstance().isCacheEnabled();
      boolean loadFromDataSource = false;

      ConfigManager.logger.debug("Cache Enabled: " + cacheEnabled);

      if (cacheEnabled) {
        cacheProvider = CacheProviderFactory.getInstance();
      }

      ConfigManager.logger.debug("Request Path: " + request.getPath());
      ConfigManager.logger.debug("Request Name: " + request.getName());

      if (request.getPath() != null && !request.getPath().isEmpty()) {
        if ( request.isPathContainsName() || (request.getName() != null && !request.getName().isEmpty()) ) {
          DataSet dataSetTmp = null;

          String cacheKey = "";
          if (cacheEnabled && request.isLoadFromCache()) {
             cacheKey = SystemUtils.getCacheKey(request.getPath(), request.getName(), false);
             dataSetTmp = (DataSet) cacheProvider.getDataSet(cacheKey);

             // Not in the cache, update cache shortly.
             if (dataSetTmp == null) {
               loadFromDataSource = true;
             } else { // In the cache, but we need to check whether it has been modified.
               if (request.isCheckForUpdate()) {
                 if (cacheProvider.isDataSetChanged(dataSetTmp, dataSourceProvider, request.isLoadData())) { // Has been modified.
                   loadFromDataSource = true;
                 }
               }
             }
          } else {
            loadFromDataSource = true;
          }

          ConfigManager.logger.debug("Load From DataSource: " + loadFromDataSource);

          if (loadFromDataSource) {
            dataSetTmp = dataSourceProvider.getDataSetByPathAndName(request.getPath(), request.getName(), request.isLoadData(), request.isLoadDescendent(), request.isLoadParent());

            if (dataSetTmp != null) {
              ConfigManager.logger.debug("DataSet Name: " + dataSetTmp.getName());
              ConfigManager.logger.debug("DataSet Path: " + dataSetTmp.getPath());
            }
            
            if (cacheEnabled && request.isLoadFromCache()) {
              cacheProvider.setDataSet(cacheKey, dataSetTmp);
            }
          }

          dataSets.add(dataSetTmp);

        } else {
          List<DataSet> dataSetTmps = null;
          String cacheKey = "";

          if (cacheEnabled && request.isLoadFromCache()) {
            cacheKey = SystemUtils.getCacheKey(request.getPath(), null, true);
            dataSetTmps = (ArrayList<DataSet>) cacheProvider.getDataSet(cacheKey);

            if (dataSetTmps == null) {
              loadFromDataSource = true;
            } else {
              if (request.isCheckForUpdate()) {
                if (cacheProvider.isDataSetsChanged(dataSetTmps, SystemUtils.removeListSuffix(cacheKey), dataSourceProvider, false)) {
                  loadFromDataSource = true;
                }
              }
            }
          } else {
            loadFromDataSource = true;
          }

          ConfigManager.logger.debug("Load From DataSource: " + loadFromDataSource);

          if (loadFromDataSource) {
            dataSetTmps = dataSourceProvider.getDataSetsByPath(request.getPath(), request.isLoadData());
            
            if (cacheEnabled && request.isLoadFromCache()) {
              cacheProvider.setDataSets(cacheKey, (ArrayList<DataSet>)dataSetTmps);
            }
          }

          if (dataSetTmps != null) {
            dataSets.addAll(dataSetTmps);
          }
        }
      }
    }

    response.setDataSets(dataSets);

    return response;
  }
}